package com.cy.sca.api.aspect;

import com.cy.sca.api.feign.RemoteNoticeService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Aspect     //声明这个类是个切面
@Component  //交给spring容器管理
public class LogAspect {
    //构建日志规范对象这里用到了门面模式
    private static final Logger log =
            LoggerFactory.getLogger(LogAspect.class);

    /**
     * 基于@Pointcut注解定义切入点
     * 切入点的定义，这里表示由RequiredLog注解 描述的方法为一个 切入点方法
     */
    @Pointcut("@annotation(com.cy.sca.api.annotation.RequiredLog)")
    public void doLog(){}//承载切入点表达式的定义，方法不写任何内容

    /**
     *通知方法（@Around）
     * @param joinPoint 连接点（封装要调用的目标方法信息
     * @return 目标方法的返回结果
     * @throws Throwable
     */
    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
        Map<String,Object> logInfo = new HashMap<>();
        //获取目标类的类全路径
        String TargetClassName = joinPoint.getTarget().getClass().getName();
        //System.out.println("TargetClassName= "+TargetClassName);
        logInfo.put("TargetClassName",TargetClassName);
        //获取目标方法的方法签名，通过签名获取方法名
        Signature signature = joinPoint.getSignature();//方法签名，包含方法信息
        String methodName = signature.getName();
        //System.out.println("methodName= "+methodName);
        logInfo.put("methodName",methodName);
        //获取目标方法执行时的传入参数，返回的数组通过jackson类的json转换string方法，返回结果
        Object[] args = joinPoint.getArgs();
        //基于第三方jackson实现将对象转换就json串的操作
        String json = new ObjectMapper().writeValueAsString(args);
        //System.out.println("jsonArgs= "+json);
        logInfo.put("jsonArgs",json);

        long t1 = System.currentTimeMillis();
        System.out.println("start: "+t1);
        try {
            Object result = joinPoint.proceed();//执行切面链(切面链[执行链]中的最终执行的方法为目标方法)
            long t2 = System.currentTimeMillis();
            long time = t2 - t1;
            System.out.println("after: "+t2);
            logInfo.put("status",1);
            logInfo.put("usedTime",time);
            System.out.println("duration: "+(t2-t1)+"ms");
            return result;
        }catch (Throwable e){
            long t3 = System.currentTimeMillis();
            long time = t3 - t1;
            System.out.println("error: "+t3);
            System.out.println("duration: "+(t3-t1)+"ms");
            logInfo.put("status",0);
            logInfo.put("usedTime",time);
            logInfo.put("errorMsg",e.getMessage());
            throw e;
        }finally {
            //将logInfo传递给用于进行日志记录或发送的服务
            log.info(" operation log {} ",logInfo.toString());
            remoteNoticeService.doLoginfo(logInfo);
        }
    }
    @Autowired
    private RemoteNoticeService remoteNoticeService;
}
